using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;

namespace StartMenuSearcher
{
	internal static class GlobalHotkeys
	{
		

		[DllImport("user32", SetLastError = true)]
		private static extern int RegisterHotKey(IntPtr hwnd, int id, int fsModifiers, int vk);
		[DllImport("user32", SetLastError = true)]
		private static extern int UnregisterHotKey(IntPtr hwnd, int id);
		[DllImport("kernel32", SetLastError = true)]
		private static extern short GlobalAddAtom(string lpString);
		[DllImport("kernel32", SetLastError = true)]
		private static extern short GlobalDeleteAtom(short nAtom);

		private static HandleForm handle = new HandleForm();

		// the id for the hotkey
		private static short hotkeyID = 0;

		public static event EventHandler KeyPressed;

		// register a global hot key
		public static void Register(Keys hotkey, KeyModifiers modifiers)
		{
			try
			{
				if (hotkeyID != 0)
				{
					Unregister();
				}

				// use the GlobalAddAtom API to get a unique ID (as suggested by MSDN docs)
				string atomName = Thread.CurrentThread.ManagedThreadId.ToString("X8");
				hotkeyID = GlobalAddAtom(atomName);
				if (hotkeyID == 0)
				{
					throw new Exception("Unable to generate unique hotkey ID. Error code: " +
						 Marshal.GetLastWin32Error().ToString());
				}

				// register the hotkey, throw if any error
				if (RegisterHotKey(handle.Handle, hotkeyID, (int)modifiers, (int)hotkey) == 0)
				{
					throw new Exception("Unable to register hotkey. Error code: " + Marshal.GetLastWin32Error()
						 .ToString());
				}
			}
			catch (Exception)
			{
				// clean up if hotkey registration failed
				Unregister();
				throw;
			}
		}

		// unregister a global hotkey
		public static void Unregister()
		{
			if (hotkeyID != 0)
			{
				UnregisterHotKey(handle.handlePtr, hotkeyID);
				// clean up the atom list
				GlobalDeleteAtom(hotkeyID);
				hotkeyID = 0;
			}
		}

		private static void OnKeyPressed()
		{
			KeyPressed(null, new EventArgs());
		}

		private class HandleForm : Form
		{
			public IntPtr handlePtr;

			public HandleForm()
			{
				this.handlePtr = Handle;
			}

			protected override void WndProc(ref System.Windows.Forms.Message m)
			{
				// let the base class process the message
				base.WndProc(ref m);

				// if this is a WM_HOTKEY message, notify the parent object
				const int WM_HOTKEY = 0x312;
				if (m.Msg == WM_HOTKEY)
				{
					OnKeyPressed();
				}
			}

			protected override void Dispose(bool disposing)
			{
				base.Dispose(disposing);
			}

			~HandleForm()
			{
				Unregister();
			}
		}
	}
}
